package com.chongchong.flow.offline.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.chongchong.flow.constant.FlowApprovalType;
import com.chongchong.flow.constant.FlowTaskStatus;
import com.chongchong.flow.exception.FlowOperationException;
import com.chongchong.flow.offline.service.IFlowOfflineOperationService;
import com.chongchong.flow.service.IFlowApiService;
import com.chongchong.core.tool.api.R;
import com.chongchong.flow.constant.FlowApprovalType;
import com.chongchong.flow.constant.FlowTaskStatus;
import com.chongchong.flow.entity.FlowTaskComment;
import com.chongchong.flow.exception.FlowOperationException;
import com.chongchong.flow.offline.service.IFlowOfflineOperationService;
import com.chongchong.flow.service.IFlowApiService;
import com.chongchong.flow.service.IFlowTaskCommentService;
import com.chongchong.flow.service.IFlowWorkOrderService;
import com.chongchong.online.entity.OnlineColumn;
import com.chongchong.online.entity.OnlineDatasourceRelation;
import com.chongchong.online.entity.OnlineTable;
import com.chongchong.online.entity.constant.RelationType;
import com.chongchong.online.object.ColumnData;
import com.chongchong.online.service.IOnlineOperationService;
import com.chongchong.online.util.OnlineOperationHelper;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;

@Slf4j
//@AllArgsConstructor
@Service("flowOfflineOperationService")
public class FlowOfflineOperationServiceImpl implements IFlowOfflineOperationService {
	@Autowired
    private IFlowApiService flowApiService;
	@Autowired
    private IFlowWorkOrderService flowWorkOrderService;
	@Autowired
    private IOnlineOperationService onlineOperationService;
	@Autowired
    private OnlineOperationHelper onlineOperationHelper;

	@Autowired
	private IFlowTaskCommentService flowTaskCommentService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveNewAndStartProcess(
            String processDefinitionId,
            FlowTaskComment flowTaskComment,
            JSONObject taskVariableData,
            OnlineTable table,
            List<ColumnData> columnDataList) {
        Object dataId = onlineOperationService.saveNew(table, columnDataList);
        ProcessInstance instance =
                flowApiService.startAndTakeFirst(processDefinitionId, dataId, flowTaskComment, taskVariableData);
        flowWorkOrderService.saveNew(instance, dataId, table.getTableId(), null);
		//更新业务数据状态
		ColumnData data = new ColumnData();
		OnlineColumn column = new OnlineColumn();
		column.setColumnName("status");
		data.setColumn(column);
		data.setColumnValue(flowTaskComment.getTaskName()+"_"+flowTaskComment.getApprovalType());
		columnDataList.add(data);
		onlineOperationService.update(table,columnDataList);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveDraft(
            String processDefinitionId,
            FlowTaskComment flowTaskComment,
            JSONObject taskVariableData,
            OnlineTable masterTable,
            List<ColumnData> masterColumnDataList,
            Map<OnlineDatasourceRelation, List<List<ColumnData>>> slaveColumnDataListMap) {
        Object dataId = onlineOperationService.saveNewAndSlaveRelation(
                masterTable, masterColumnDataList, slaveColumnDataListMap);

//        ProcessInstance instance =
//                flowApiService.startAndTakeFirst(processDefinitionId, dataId, flowTaskComment, taskVariableData);
//        flowWorkOrderService.saveNew(instance, dataId, masterTable.getTableId(), null);
    }

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void saveDraft(
		String processDefinitionId,
		FlowTaskComment flowTaskComment,
		JSONObject taskVariableData,
		OnlineTable table,
		List<ColumnData> columnDataList) {
		Object dataId = onlineOperationService.saveNew(table, columnDataList);


//		ProcessInstance instance =
//			flowApiService.startAndTakeFirst(processDefinitionId, dataId, flowTaskComment, taskVariableData);
//		flowWorkOrderService.saveNew(instance, dataId, table.getTableId(), null);
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void saveNewAndStartProcess(
		String processDefinitionId,
		FlowTaskComment flowTaskComment,
		JSONObject taskVariableData,
		OnlineTable masterTable,
		List<ColumnData> masterColumnDataList,
		Map<OnlineDatasourceRelation, List<List<ColumnData>>> slaveColumnDataListMap) {
		Object dataId = onlineOperationService.saveNewAndSlaveRelation(
			masterTable, masterColumnDataList, slaveColumnDataListMap);
		ProcessInstance instance =
			flowApiService.startAndTakeFirst(processDefinitionId, dataId, flowTaskComment, taskVariableData);
		flowWorkOrderService.saveNew(instance, dataId, masterTable.getTableId(), null);
		//更新业务数据状态
		masterColumnDataList.stream().forEach(c->{
			OnlineColumn column =c.getColumn();
			if(column.getColumnName().equals("status")){
				c.setColumnValue(flowTaskComment.getTaskName()+"_"+flowTaskComment.getApprovalType());
			}
		});
		onlineOperationService.update(masterTable,masterColumnDataList);
	}

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveNewAndTakeTask(
            String processInstanceId,
            String taskId,
            FlowTaskComment flowTaskComment,
            JSONObject taskVariableData,
            OnlineTable table,
            List<ColumnData> columnDataList) {
        Object dataId = onlineOperationService.saveNew(table, columnDataList);
        Task task = flowApiService.getProcessInstanceActiveTask(processInstanceId, taskId);
        flowApiService.setBusinessKeyForProcessInstance(processInstanceId, dataId);
        Map<String, Object> variables =
                flowApiService.initAndGetProcessInstanceVariables(task.getProcessDefinitionId());
        if (taskVariableData == null) {
            taskVariableData = new JSONObject();
        }
        taskVariableData.putAll(variables);
        flowApiService.completeTask(task, flowTaskComment, taskVariableData);
        ProcessInstance instance = flowApiService.getProcessInstance(processInstanceId);
        flowWorkOrderService.saveNew(instance, dataId, table.getTableId(), null);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveNewAndTakeTask(
            String processInstanceId,
            String taskId,
            FlowTaskComment flowTaskComment,
            JSONObject taskVariableData,
            OnlineTable masterTable,
            List<ColumnData> masterColumnDataList,
            Map<OnlineDatasourceRelation, List<List<ColumnData>>> slaveColumnDataListMap) {
        Object dataId = onlineOperationService.saveNewAndSlaveRelation(
                masterTable, masterColumnDataList, slaveColumnDataListMap);
        Task task = flowApiService.getProcessInstanceActiveTask(processInstanceId, taskId);
        flowApiService.setBusinessKeyForProcessInstance(processInstanceId, dataId);
        Map<String, Object> variables =
                flowApiService.initAndGetProcessInstanceVariables(task.getProcessDefinitionId());
        if (taskVariableData == null) {
            taskVariableData = new JSONObject();
        }
        taskVariableData.putAll(variables);
        flowApiService.completeTask(task, flowTaskComment, taskVariableData);
        ProcessInstance instance = flowApiService.getProcessInstance(processInstanceId);
        flowWorkOrderService.saveNew(instance, dataId, masterTable.getTableId(), null);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateAndTakeTask(
            Task task,
            FlowTaskComment flowTaskComment,
            JSONObject taskVariableData,
            OnlineTable masterTable,
            JSONObject masterData,
            String masterDataId,
            JSONObject slaveData,
            Long datasourceId) {
        int flowStatus = FlowTaskStatus.APPROVING;
        if (flowTaskComment.getApprovalType().equals(FlowApprovalType.REFUSE)) {
            flowStatus = FlowTaskStatus.REFUSED;
        }
        flowWorkOrderService.updateFlowStatusByProcessInstanceId(task.getProcessInstanceId(), flowStatus);
        this.handleMasterTableData(masterTable, masterData, masterDataId);
        if (slaveData != null) {
            for (Map.Entry<String, Object> relationEntry : slaveData.entrySet()) {
                Long relationId = Long.parseLong(relationEntry.getKey());
                this.handleSlaveTableData(
                        relationId, relationEntry.getValue(), datasourceId, masterTable, masterData, masterDataId);
            }
        }
        flowApiService.completeTask(task, flowTaskComment, taskVariableData);
		//更新业务数据状态
		R<List<ColumnData>> columnDataListResult =
			onlineOperationHelper.buildTableData(masterTable, masterData, true, null);
		List<ColumnData> masterColumnDataList = columnDataListResult.getData();
		masterColumnDataList.stream().forEach(c->{
			OnlineColumn column =c.getColumn();
			if(column.getColumnName().equals("status")){
				c.setColumnValue(flowTaskComment.getTaskName()+"_"+flowTaskComment.getApprovalType());
			}
		});
		onlineOperationService.update(masterTable,masterColumnDataList);
    }

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void updateDraft(String processDefinitionId, FlowTaskComment flowTaskComment, JSONObject taskVariableData,
							OnlineTable table, List<ColumnData> columnDataList) {
		Object dataId = onlineOperationService.update(table, columnDataList);

	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void updateDraft(String processDefinitionId, FlowTaskComment flowTaskComment,
							JSONObject taskVariableData, OnlineTable masterTable, List<ColumnData> masterColumnDataList,
							Map<OnlineDatasourceRelation, List<List<ColumnData>>> slaveColumnDataListMap) {
		onlineOperationService.updateMasterAndSlaveRelation(masterTable,masterColumnDataList,slaveColumnDataListMap);
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void updateAndStartProcess(Long masterDataId,String processDefinitionId, FlowTaskComment flowTaskComment,
									  JSONObject taskVariableData, OnlineTable table, List<ColumnData> columnDataList) {
		//onlineOperationService.update(table, columnDataList);
		ProcessInstance instance =
			flowApiService.startAndTakeFirst(processDefinitionId, masterDataId, flowTaskComment, taskVariableData);
		flowWorkOrderService.saveNew(instance, masterDataId, table.getTableId(), null);
		//更新业务数据状态
		ColumnData data = new ColumnData();
		OnlineColumn column = new OnlineColumn();
		column.setColumnName("status");
		data.setColumn(column);
		data.setColumnValue(flowTaskComment.getTaskName()+"_"+flowTaskComment.getApprovalType());
		columnDataList.add(data);
		onlineOperationService.update(table,columnDataList);
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void updateAndStartProcess(Long masterDataId,String processDefinitionId, FlowTaskComment flowTaskComment,
										 JSONObject taskVariableData, OnlineTable masterTable,
										 List<ColumnData> masterColumnDataList,
										 Map<OnlineDatasourceRelation, List<List<ColumnData>>> slaveColumnDataListMap) {
		//修改主表和从表信息
		onlineOperationService.updateMasterAndSlaveRelation(masterTable, masterColumnDataList, slaveColumnDataListMap);

		ProcessInstance instance =
			flowApiService.startAndTakeFirst(processDefinitionId, masterDataId, flowTaskComment, taskVariableData);
		flowWorkOrderService.saveNew(instance, masterDataId, masterTable.getTableId(), null);
		//更新业务数据状态
		masterColumnDataList.stream().forEach(c->{
			OnlineColumn column =c.getColumn();
			if(column.getColumnName().equals("status")){
				c.setColumnValue(flowTaskComment.getTaskName()+"_"+flowTaskComment.getApprovalType());
			}
		});
		onlineOperationService.update(masterTable,masterColumnDataList);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void saveOrUpdateMasterAndSlave(OnlineTable masterTable, JSONObject masterData, String masterDataId, JSONObject slaveData, Long datasourceId, FlowTaskComment flowTaskComment) {
		this.handleMasterTableData(masterTable, masterData, masterDataId);
		if (slaveData != null) {
			for (Map.Entry<String, Object> relationEntry : slaveData.entrySet()) {
				Long relationId = Long.parseLong(relationEntry.getKey());
				this.handleSlaveTableData(
					relationId, relationEntry.getValue(), datasourceId, masterTable, masterData, masterDataId);
			}
		}

	}

	private void handleMasterTableData(OnlineTable masterTable, JSONObject masterData, String dataId) {
        // 如果存在主表数据，就执行主表数据的更新。
        if (masterData != null) {
            Map<String, Object> originalMasterData =
                    onlineOperationService.getMasterData(masterTable, null, null, dataId);
            for (Map.Entry<String, Object> entry : originalMasterData.entrySet()) {
                masterData.putIfAbsent(entry.getKey(), entry.getValue());
            }
            R<List<ColumnData>> columnDataListResult =
                    onlineOperationHelper.buildTableData(masterTable, masterData, true, null);
            if (!columnDataListResult.isSuccess()) {
                throw new FlowOperationException(columnDataListResult.getMsg());
            }
            if (!onlineOperationService.update(masterTable, columnDataListResult.getData())) {
                throw new FlowOperationException("主表数据不存在！");
            }
        }
    }

    private void handleSlaveTableData(
            Long relationId,
            Object slaveData,
            Long datasourceId,
            OnlineTable masterTable,
            Map<String, Object> masterData,
            String masterDataId) {
        R<OnlineDatasourceRelation> relationResult =
                onlineOperationHelper.verifyAndGetOneToManyRelation(datasourceId, relationId);
        if (!relationResult.isSuccess()) {
            throw new FlowOperationException(relationResult.getMsg());
        }
        OnlineDatasourceRelation relation = relationResult.getData();
        OnlineTable slaveTable = relation.getSlaveTable();
        if (relation.getRelationType().equals(RelationType.ONE_TO_ONE)) {
            String keyColumnName = slaveTable.getPrimaryKeyColumn().getColumnName();
            JSONObject relationData = ((JSONArray) slaveData).getJSONObject(0);
            if (MapUtil.isEmpty(relationData)) {
                return;
            }
            String slaveDataId = relationData.getString(keyColumnName);
            if (slaveDataId == null) {
                R<List<ColumnData>> columnDataListResult =
                        onlineOperationHelper.buildTableData(slaveTable, relationData, false, null);
                if (!columnDataListResult.isSuccess()) {
                    throw new FlowOperationException(columnDataListResult.getMsg());
                }
                onlineOperationService.saveNew(slaveTable, columnDataListResult.getData());
            } else {
                Map<String, Object> originalSlaveData =
                        onlineOperationService.getMasterData(slaveTable, null, null, slaveDataId);
                for (Map.Entry<String, Object> entry : originalSlaveData.entrySet()) {
                    //relationData.putIfAbsent(entry.getKey(), entry.getValue());
					if (!relationData.containsKey(entry.getKey())){
						relationData.put(entry.getKey(), entry.getValue());
					}
                }
                R<List<ColumnData>> columnDataListResult =
                        onlineOperationHelper.buildTableData(slaveTable, relationData, true, null);
                if (!columnDataListResult.isSuccess()) {
                    throw new FlowOperationException(columnDataListResult.getMsg());
                }
                if (!onlineOperationService.update(slaveTable, columnDataListResult.getData())) {
                    throw new FlowOperationException("关联从表 [" + slaveTable.getTableName() + "] 中的更新数据不存在");
                }
            }
        } else if (relation.getRelationType().equals(RelationType.ONE_TO_MANY)) {
            JSONArray relationDataArray = (JSONArray) slaveData;
            if (CollUtil.isEmpty(relationDataArray)) {
                return;
            }
            JSONObject firstData = relationDataArray.getJSONObject(0);
            Object key = firstData.get(slaveTable.getPrimaryKeyColumn().getColumnName());
            // 如果一对多关联数据中存在主键数据，则需要先批量删除。
            if (key != null) {
                OnlineColumn slaveColumn = relation.getSlaveTable().getColumnMap().get(relation.getSlaveColumnId());
                Object relationSlaveColumnValue = firstData.get(slaveColumn.getColumnName());
                onlineOperationService.forceDelete(
                        relation.getSlaveTable(), slaveColumn, relationSlaveColumnValue.toString());
            }
            if (masterData == null) {
                masterData = onlineOperationService.getMasterData(
                        masterTable, null, null, masterDataId);
            }
            for (int i = 0; i < relationDataArray.size(); i++) {
                JSONObject relationSlaveData = relationDataArray.getJSONObject(i);
                // 自动补齐主表关联数据。
                OnlineColumn masterColumn = masterTable.getColumnMap().get(relation.getMasterColumnId());
                Object masterColumnValue = masterData.get(masterColumn.getColumnName());
                OnlineColumn slaveColumn = slaveTable.getColumnMap().get(relation.getSlaveColumnId());
                relationSlaveData.put(slaveColumn.getColumnName(), masterColumnValue);
				//主键置空
				relationSlaveData.put(slaveTable.getPrimaryKeyColumn().getColumnName(),null);
                // 拆解主表和一对多关联从表的输入参数，并构建出数据表的待插入数据列表。
                R<List<ColumnData>> columnDataListResult =
                        onlineOperationHelper.buildTableData(slaveTable, relationSlaveData, false, null);
                if (!columnDataListResult.isSuccess()) {
                    throw new FlowOperationException(columnDataListResult.getMsg());
                }
                onlineOperationService.saveNew(slaveTable, columnDataListResult.getData());
            }
        }
    }
}
